﻿using JESAI.DistributedLock.Internal;
using System;

namespace JESAI.DistributedLock.MySql;

/// <summary>
/// 指定连接MySQL数据库和锁定MySQL数据库的选项
/// </summary>
public sealed class MySqlConnectionOptionsBuilder
{
    private TimeoutValue? _keepaliveCadence;
    private bool? _useMultiplexing;

    internal MySqlConnectionOptionsBuilder() { }

    /// <summary>
    /// MySQL的wait_timeout系统变量决定了服务器在终止连接之前允许连接空闲多长时间。
    /// 有关更多信息，请参见 https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_wait_timeout.
    /// 
    /// 为了防止这种情况，此选项设置了在持有锁的连接上运行无操作“keepalive”查询的节奏。
    /// 
    /// 因为MySQL的默认设置是8小时，所以默认的<paramref name="keepaliveCadence"/>是3.5小时。
    /// 
    /// 设置值<see cref="Timeout.InfiniteTimeSpan"/>将禁用keepalive。
    /// </summary>
    public MySqlConnectionOptionsBuilder KeepaliveCadence(TimeSpan keepaliveCadence)
    {
        this._keepaliveCadence = new TimeoutValue(keepaliveCadence, nameof(keepaliveCadence));
        return this;
    }

    /// <summary>
    /// 这种模式利用了这样一个事实，即在“持有”锁（或其他同步原语）时，连接基本上是空闲的。因此，通常可以多路复用共享连接，以便该连接可以同时持有多个锁，而不是为每个持有的锁创建新的连接。
    /// 
    /// 默认情况下，多路复用处于打开状态。
    /// 
    /// 这是以这样的方式实现的，即释放此类连接上持有的锁永远不会被等待获取同一连接上的锁的Acquire（）调用阻止。因此，多路复用策略是“乐观的”：如果在共享连接上无法立即获取锁，则将分配一个新的（可共享的）连接。
    /// 
    /// 此选项可以提高性能，避免高负载情况下的连接池不足。它也是特别适用于使用零长度超时的<see cref="IDistributedLock.TryAcquire(TimeSpan, System.Threading.CancellationToken)"/>语义的情况。
    /// </summary>
    public MySqlConnectionOptionsBuilder UseMultiplexing(bool useMultiplexing = true)
    {
        this._useMultiplexing = useMultiplexing;
        return this;
    }

    internal static (TimeoutValue keepaliveCadence, bool useMultiplexing) GetOptions(Action<MySqlConnectionOptionsBuilder>? optionsBuilder)
    {
        MySqlConnectionOptionsBuilder? options;
        if (optionsBuilder != null)
        {
            options = new MySqlConnectionOptionsBuilder();
            optionsBuilder(options);
        }
        else
        {
            options = null;
        }

        var keepaliveCadence = options?._keepaliveCadence ?? TimeSpan.FromHours(3.5);
        var useMultiplexing = options?._useMultiplexing ?? true;

        return (keepaliveCadence, useMultiplexing);
    }
}
